package androidtopc;

import java.awt.image.BufferedImage;
import java.io.*;
import java.net.*;

import javax.imageio.ImageIO;

public class Server {
	private ServerSocket server;
	private Socket socket;
	private DataOutputStream out;
	private DataInputStream in;
	private final int PORT = 2004;
	private final int BACKLOG = 0;
	// File location and type
	private final String HOME_DIR = "C:/dev/UROP/images/";
	private final String IMAGE_TYPE = "jpg";
	private final String IMAGE_EXTENSION = "." + IMAGE_TYPE;
	// Size of the android buffer
	private final int BUFFER_SIZE = (int) Math.pow(2, 15); 
	
	Server() {
	}

	void run() {
		try {
			// Create a server socket
			server = new ServerSocket(PORT, BACKLOG);
			server.setReceiveBufferSize(BUFFER_SIZE);
			connect();

			int temp = 0;
			while (true) {
				receiveMessage();
				receiveAndSaveImage(HOME_DIR + "received" + temp
						+ IMAGE_EXTENSION);
				temp++;
			}
		} catch (IOException ioException) {
			ioException.printStackTrace();
		} finally {
			closeConnection();
		}
	}

	/**
	 * Connect to the client and create input and output streams
	 */
	void connect() {
		try {
			// Listen for and accept connection
			System.out.println("\nWaiting for connection");
			socket = server.accept();
			System.out.println("Connection received from "
					+ socket.getInetAddress().getHostName());

			// Get Input and Output streams
			in = new DataInputStream(socket.getInputStream());
			out = new DataOutputStream(socket.getOutputStream());
			out.flush();

			sendMessage("Connection successful");

		} catch (IOException e) {
			System.err.println("Error while attempting to connect to client: "
					+ e.getMessage());
		}

	}
	
	/**
	 * Close the connection between the server and client
	 */
	void closeConnection(){
		try {
			in.close();
			out.close();
			server.close();
		} catch (IOException ioException) {
			ioException.printStackTrace();
		}
	}
	/**
	 * Send a message to the client.
	 */
	void sendMessage(String msg) {
		try {
			out.writeUTF(msg);
			out.flush();
			System.out.println("server> " + msg);
		} catch (IOException ioException) {
			System.err.println("Send message error: "
					+ ioException.getMessage());
		}
	}

	/**
	 * Receive a message from the client.
	 */
	void receiveMessage() {
		try {
			System.out.println("client> " + in.readUTF());
		} catch (IOException ioException) {
			System.err.println("Receive message error: "
					+ ioException.getMessage());
		}
	}

	/**
	 * Save the given image in the file location provided
	 * @param image	The image to save
	 * @param filePath	where to save the image
	 */
	void saveImage(BufferedImage image, String filePath) {
		try {
			File outputfile = new File(filePath);
			ImageIO.write(image, IMAGE_TYPE, outputfile);
		} catch (IOException e) {
			System.err.print("Save image error: " + e.getMessage());
		}
	}

	/**
	 * Receive an image from the client and save it.
	 * @param filePath
	 */
	void receiveAndSaveImage(String filePath) {
		try {
			// Read header
			int imageSize = in.readInt();

			// Byte array to store the image
			byte[] byteImage = new byte[imageSize];
			// Number of full buffers that will be transmitted
			int numStreams = imageSize / BUFFER_SIZE;
			System.out.println("server> Incoming Image Size: " + imageSize
					+ ", Buffers: " + numStreams);
			
			// Add the buffer-sized streams to the image.
			for (int i = 0; i < numStreams; i++) {
				// Get the buffer
				byte[] buffer = new byte[BUFFER_SIZE];
				in.read(buffer);

				// Add byte value to the final array
				int startIndex = i * BUFFER_SIZE;
				System.arraycopy(buffer, 0, byteImage, startIndex,
						buffer.length);
			}
			// add the bytes from the remaining stream
			byte[] buffer = new byte[imageSize - numStreams * BUFFER_SIZE];
			in.read(buffer);
			System.arraycopy(buffer, 0, byteImage, byteImage.length
					- buffer.length, buffer.length);
			
			// Confirm that the image has been recieved
			out.writeBoolean(true);
			
			// Save the image
			BufferedImage bimg = byteToBufferedImage(byteImage, IMAGE_TYPE);
			saveImage(bimg, filePath);
		} catch (IOException e) {
			System.err.print("Could not receive image");
		}
	}

	/**
	 * Convert a byte array into a buffered image.
	 * @param byteImage The image in byte form
	 * @param imageType The type of image to produce (.jpg, .gif, etc.)
	 * @return A buffered image generated from the file
	 */
	private BufferedImage byteToBufferedImage(byte[] byteImage, String imageType) {
		try {
			// create a byte input stream, add the image, convert it to a buffered image
			InputStream input = new ByteArrayInputStream(byteImage);
			BufferedImage bimg = ImageIO.read(input);
			return bimg;
		} catch (IOException e) {
			System.err
					.println("Could not converted byte image to buffered image: " + e.getMessage());
			return null;
		}
	}

	public static void main(String args[]) {
		Server server = new Server();
		while (true) {
			server.run();
		}

	}
}